﻿// See https://aka.ms/new-console-template for more information
//装饰器模式是一种机构型模式，他允许在不改变对象自身的基础上，动态的添加额外的功能。他通过将对象包装在一个装饰器对象中，从而使得在运行时可以灵活地给一个对象添加新的行为或者修改原有的行为
//在软件开发时，有时候我们不能使用继承对系统进行扩展，比如我们想要扩展的类是一个密封类。或者使用继承不利于系统的扩展和维护，比如系统中存在大量独立扩展，为支持每一种扩展或扩展之间的组合将产生大量的子类，不利于系统维护。这时我们就可以使用装饰器模式，通过关联关系来代替继承关系，从而实现上述问题的解决。
//对新房进行装修并没有改变房屋用于居住的本质，但它可以让房子变得更加漂亮，更加温馨，更加使用，更能满足居家的需求。装饰器模式就是这样一种可以在不改变一个对象本身功能的基础上给对象增加额外的新行为，在现实生活中，这种情况也到处存在。

//现在，我们可以创建一个订单并添加各种调料来装饰咖啡
Beaverage Beaverage = new Espresso();
Console.WriteLine(Beaverage.GetDescription());
//加入摩卡调料
Beaverage = new Mocha(Beaverage);
Console.WriteLine(Beaverage.GetDescription());
//加入豆浆调料
Beaverage = new Soy(Beaverage);
Console.WriteLine(Beaverage.GetDescription());

//装饰器模式可以在不改变现有对象的前提下，通过在对象上添加一个包装饰器来动态的添加新的功能。在这个例子中，我们将使用装饰器模式来动态的添加额外的配料到咖啡中
//首先，我们定义一个抽象类Beverage（饮料），他有一个GetDescription方法和Cost方法，前者返回饮料的描述，后者返回价格
internal abstract class Beaverage
{
    public abstract string GetDescription();

    public abstract double Cost();
}

//然后，我们定义具体的饮料类，比如Exporesson浓缩咖啡，HouseBlend混合咖啡等。这些具体的饮料类继承自Beaverage类，实现其中的方法
internal class Espresso : Beaverage
{
    public override double Cost()
    {
        return 1.99;
    }

    public override string GetDescription()
    {
        return "Espresso";
    }
}

internal class HouseBlend : Beaverage
{
    public override double Cost()
    {
        return 0.89;
    }

    public override string GetDescription()
    {
        return "House Blend Coffee";
    }
}

//接下来，我们定义一个装饰器类CondimentDecorator调料装饰器，他也继承自Beverage类。CondimentDecorator有一个受保护的Beverager对象，用于包装饮料。
internal abstract class CondimentDecorator : Beaverage
{
    protected Beaverage beaverage;

    protected CondimentDecorator(Beaverage beaverage)
    {
        this.beaverage = beaverage;
    }
}

//然后，我们定义具体的调料装饰器类，比如Mocha摩卡，Soy豆浆等。这些具体的调料装饰器类也继承自CondimentDecorator类，实现其方法
//通过装饰器，我们可以在原有的功能上面增加一些步骤，使得功能更加丰富
//以下是具体的装饰器
internal class Mocha : CondimentDecorator
{
    public Mocha(Beaverage beaverage) : base(beaverage)
    {
    }

    public override double Cost()
    {
        return 0.2 + beaverage.Cost();
    }

    public override string GetDescription()
    {
        return beaverage.GetDescription() + ",Mocha";
    }
}

internal class Soy : CondimentDecorator
{
    public Soy(Beaverage beaverage) : base(beaverage)
    {
    }

    public override double Cost()
    {
        return 0.15 + beaverage.Cost();
    }

    public override string GetDescription()
    {
        return beaverage.GetDescription() + ",Soy";
    }
}